# Copyright 2018 Maco
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from blockchain.core.hash import hash_str
from blockchain.cache.cache import Mcache
from blockchain.common.constants import MINE_STATUS


def proof_of_work(prev_hash, index, tx_count):
    '''
    工作量证明
    :param prev_hash: 上一块的hash
    :param index: <int> block index
    :param tx_count: <int> 交易总数
    :return: <int> proof, if proof < 0, stop.
    '''
    proof = 0
    prefix = get_hash_prefix(index)
    while not check_proof(prev_hash, index,
                          tx_count, proof, prefix):
        if Mcache.get(MINE_STATUS):
            proof += 1
        else:
            proof = -1
            break
    return proof


def check_proof(prev_hash, index, tx_count, proof, prefix):
    '''
    验证散列值是否以指定的prefix前缀开头
    :param prev_hash: 上一块的工作量
    :param index: <int> 索引
    :param tx_count: <int> 交易总数
    :param proof: <int> 工作量
    :param prefix: <str> 指定的前缀
    :return: <bool> True 验证成功, False 验证失败
    '''
    res = hash_str(f'{prev_hash}{index}{tx_count}{proof}')
    return res[:len(prefix)] == prefix


def check_block_proof(block):
    '''
    验证块的hash头部
    :param block: 块
    :return: True通过验证，否则False
    '''
    prefix = get_hash_prefix(block['index'])
    return check_proof(block['prev_hash'], block['index'],
                       block['tx_count'], block['proof'], prefix)


def get_hash_prefix(index):
    '''
    工作量证明，函数返回的是要求hash运算以指定多少个0开头，
    例如:返回 '000',那么 hash运算结果开头是'000xxxxxxx'这种格式
    :param index: <int> block index
    :return: <str> 返回前缀
    '''
    res = index // (365 * 24 * 4)
    if res <= 2:
        return '00'
    prefix = ['0' for i in range(0, res)]
    return ''.join(prefix)
